package network

import (
	"encoding/binary"
	"io"
	"log"
	"net"

	"golang.org/x/net/websocket"
)

type WebStream struct {
	conn    *websocket.Conn
	encrypt bool
}

// 从socket读取1个封包,并返回
func (self *WebStream) Read() (p *Packet, err error) {
	//读取包头
	headdata := make([]byte, PacketHeaderSize)
	if _, err = io.ReadFull(self.conn, headdata); err != nil {
		log.Println("socket-读取出错", err)
		return nil, err
	}

	//读取MsgTag
	//msgTag := uint16(binary.BigEndian.Uint16(headdata[0:2]))

	//非法包
	//if msgTag != MSG_TAG {
	//	return nil, packetTagNotMatch
	//}

	//读取整包大小
	fullSize := uint16(binary.LittleEndian.Uint16(headdata[2:4]))

	dataSize := fullSize - PacketHeaderSize
	if dataSize < 0 {
		log.Println("数据长度错误", dataSize)
		return nil, packetDataSizeInvalid
	}

	//读取加密数据
	packData := make([]byte, dataSize)
	if _, err = io.ReadFull(self.conn, packData); err != nil {
		log.Println("数据读取错误", dataSize, len(packData), err)
		return nil, err
	}

	//效验接收到的大小
	if packData == nil || dataSize != uint16(len(packData)) {
		log.Println("数据验证错误", dataSize, len(packData), err)
		return nil, err
	}

	p, err = ToDecryptPacket(packData, 0)
	if err != nil {
		log.Println("数据解密错误", err)
		return nil, err
	}
	//log.Printf("接收数据 [%d-%d] %d", p.MainId, p.SubId, fullSize)

	return p, nil
}

// 将一个封包发送到socket
func (self *WebStream) Write(pkt *Packet) (err error) {
	buffer := make([]byte, PacketHeaderSize)

	//写MsgTag
	binary.LittleEndian.PutUint16(buffer[0:2], uint16(MSG_TAG))

	userdata := pkt.ToByteArray()

	//写MsgSize
	packetsize := len(userdata) + PacketHeaderSize
	binary.LittleEndian.PutUint16(buffer[2:4], uint16(packetsize))
	//log.Printf("发送数据 [%d-%d] %d", pkt.MainId, pkt.SubId, packetsize)

	//写数据
	buffer = append(buffer[:PacketHeaderSize], userdata...)
	if _, err = self.conn.Write(buffer); err != nil {
		log.Println("写数据", err)
		return err
	}

	return nil
}

// 关闭
func (self *WebStream) Close() error {
	return self.conn.Close()
}

// 裸socket操作
func (self *WebStream) Raw() net.Conn {
	return self.conn
}

// 封包流 relay模式: 在封包头有clientid信息
func NewWebStream(conn *websocket.Conn, encrypt bool) PacketStream {
	return &WebStream{
		conn:    conn,
		encrypt: encrypt,
	}
}
